import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

public class MatrixFactorization {
	static UtmRwr_Model utm = new UtmRwr_Model(0, 0, 0);
	static ArrayList<Integer> allUsers = new ArrayList<Integer>();
	static ArrayList<Integer> allMovies = new ArrayList<Integer>();
	static ArrayList<Integer> allGroups = new ArrayList<Integer>();
	public static HashMap<String,String> arguments;
	static PrintStream out = System.out;
	static PrintStream ps;
	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		
		arguments = new HashMap<String,String>();
		
		for (int i = 0; i < args.length; i += 2) {
			arguments.put(args[i], args[i+1]);
		}
			
//		readData();
//		gmRating(UtmRwr_Model.Policy.avg);
		
//		finalResultsFromPreGMRating(UtmRwr_Model.Policy.lm, "lm_gmrating_result.csv");
		
		finalResultsFromPreUMRating(UtmRwr_Model.Policy.wtd, "umrating_result.csv");
		
//		for(UtmRwr_Model.Policy tmp : UtmRwr_Model.Policy.values())
//		{
////			finalResultsFromPreUMRating(tmp, "umrating_result.csv");
//			finalResultsFromPreGMRating(tmp, "wtd_gmrating_result.csv");
//		}
		
		System.setOut(out);
	}
	
	//redirect output to file
	static void redirect()
	{
		try {
			ps = new PrintStream("test.txt");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.setOut(ps);
	}
	
	// 读书据存储为csv格式
	static void readData() throws Exception{
		System.out.println("Reading data...");
		float[][] umrating;
		Class.forName("com.mysql.jdbc.Driver"); // 加载MYSQL JDBC驱动程序
		Connection connect = DriverManager.getConnection(
				"jdbc:mysql://localhost:3306/rs_train0325_group", "root",
				"040016");
		Statement stmt = connect.createStatement(
				ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
		ResultSet murs = stmt.executeQuery("select * from user_movie");

		murs.last();
		umrating = new float[murs.getRow()][3];
		murs.beforeFirst();

		int row = 0;
		int uid, mid, value;
		while (murs.next()) {
			System.out.println("retrieving row "+row);
			uid = murs.getInt("userid");
			mid = murs.getInt("movieid");
			value = murs.getInt("value");

			if (!allUsers.contains(uid))
				allUsers.add(uid);
			if (!allMovies.contains(mid))
				allMovies.add(mid);
			umrating[row][0] = allUsers.indexOf(uid);
			umrating[row][1] = allMovies.indexOf(mid);
			umrating[row][2] = value;
			row++;
		}
		System.out.println("umrating ready, writing matrix to file...");
		UtmRwr_Model.matrixToFile(UtmRwr_Model.Model.pmf, umrating, "umrating.csv");
	}
	
	/**
	 * To calculate gmrating corresponding to the specified policy
	 * @param policy
	 * @throws Exception 
	 */
	// 读数据并计算出gmrating （三种策略）
	
	static void gmRating(UtmRwr_Model.Policy policy) throws Exception{
//		String model = arguments.get("-model");
//		String filename = arguments.get("-input");
//		utm.readDocs(filename);
		utm.readDocs(null);
		float[][] gmr = new float[utm.G][utm.M];
		int count=0;
		
		for (int g = 0; g < utm.G; g++) {
			float sumOfNum = 0;
			for (int n : utm.allGroups[g].users.values()) {
				sumOfNum += n;
			}
			for (int m = 0; m < utm.M; m++) {
				float preAllGMRating = (policy==UtmRwr_Model.Policy.lm)?Integer.MAX_VALUE:0;
				for (Entry<Integer, Integer> user : utm.allGroups[g].users.entrySet()) {
					if (!utm.allMovies[m].users.containsKey(user.getKey()))
						continue;
					switch(policy){//change
					case wtd:
						preAllGMRating += user.getValue() / sumOfNum * utm.allMovies[m].users.get(user.getKey());
						break;
					case lm:
						preAllGMRating = Math.min(preAllGMRating, utm.allMovies[m].users.get(user.getKey()));
//						if(preAllGMRating==0)
//						{
//							System.out.println();
//						}
						break;
					case avg:
						preAllGMRating += utm.allMovies[m].users.get(user.getKey());
						break;
					}
				}
				
				
				if(preAllGMRating==Integer.MAX_VALUE || preAllGMRating==0)
				{
//					//test
//					if(preAllGMRating==0)
//					{
//						System.out.println();
//					}
					preAllGMRating=-1;
				}
				else {
					count++;
					if (policy == UtmRwr_Model.Policy.avg)
						preAllGMRating /= utm.allGroups[g].users.size();
				}
				gmr[g][m] = preAllGMRating;
			}
		}
		
		//test-2014-05-13
				for(int m=0;m<utm.M;++m)
				{
					boolean flag = false;
					for(int g=0;g<utm.G;++g)
					{
						if(gmr[g][m]!=-1)
						{
							flag = true;
							break;
						}
					}
					if(!flag)
					{
						System.out.println(m);
					}
				}
		
		ArrayList<Integer> allGroups = new ArrayList<Integer>();
		for(int g=0;g<utm.G;g++)
			allGroups.add(utm.allGroups[g].gid);
		float[][] gmrating = new float[count][3];
		int row=0;
		for(int g = 0;g<gmr.length;g++){
			for(int m=0;m<gmr[g].length;m++){
				if(gmr[g][m]!=-1){
					gmrating[row][0] = g;
					gmrating[row][1] = m;
					//2014-05-08
					if(gmr[g][m]!=0)
						gmrating[row][2]=gmr[g][m];
					else
						gmrating[row][2]=(float) 1e-6;
//					gmrating[row][2] = gmr[g][m];
					row++;
				}
			}
		}
		arrayListToFile(UtmRwr_Model.Model.pmf, policy, allGroups, "allGroups.csv");
		System.out.println("-------"+policy+"_gmrating ready, matrix to file-------");
		UtmRwr_Model.matrixToFile(UtmRwr_Model.Model.pmf, policy,gmrating, policy+"_gmrating.csv");
	}
	
	/**
	 * 给定策略和preGMRating矩阵文件，计算mae、auc、prs、map.<br>
	 * 参数policy须与preGMRating所用的策略对应
	 * @param policy
	 * @param preGMRatingFile
	 * @throws Exception
	 */
	static void finalResultsFromPreGMRating(UtmRwr_Model.Policy policy,String preGMRatingFile) throws Exception{
//		String filename = arguments.get("-input");
//		utm.readDocs(filename);
		utm.Z = Integer.parseInt(arguments.get("-Z"));
		utm.readDocs(null);
		utm.initialize();
		System.out.println(policy+" policy...");
		utm.calculateTestGMRating(policy);
		utm.fileToMatrix(UtmRwr_Model.Model.pmf, policy, utm.preGMRating, preGMRatingFile);
		utm.maeAucPcsMapRecall(UtmRwr_Model.Model.pmf,policy);
	}
	
	/**
	 * 给定策略和preUMRating矩阵文件，计算mae、auc、prs、map
	 * @param policy
	 * @param preUMRatingFile
	 * @throws Exception
	 */
	static void finalResultsFromPreUMRating(UtmRwr_Model.Policy policy,String preUMRatingFile) throws Exception{
//		String filename = arguments.get("-input");
		utm.Z = Integer.parseInt(arguments.get("-Z"));
		utm.readDocs(null);
		utm.initialize();
		System.out.println(policy+" policy...");
//		utm.calculateTestGMRating(policy);
		utm.fileToMatrix(utm.preUMRating, preUMRatingFile);
		// predicting all rating of movies by all groups
//		switch (policy) {
//		case wtd:
//			for (int g = 0; g < utm.G; g++) {
//				float sumOfNum = 0;
//				for (int n : utm.allGroups[g].users.values())
//					sumOfNum += n;
//				for (int m = 0; m < utm.M; m++) {
//					for (Entry<Integer, Integer> user : utm.allGroups[g].users
//							.entrySet()) {
//						utm.preGMRating[g][m] += user.getValue()
//								/ sumOfNum
//								* utm.preUMRating[utm.userListTrain
//										.indexOf(user.getKey())][m];
//					}
//				}
//			}
//			break;
//		case lm:
//			for (int g = 0; g < utm.G; g++) {
//				for (int m = 0; m < utm.M; m++) {
//					utm.preGMRating[g][m] = Integer.MAX_VALUE;
//					for (Entry<Integer, Integer> user : utm.allGroups[g].users
//							.entrySet()) {
//						utm.preGMRating[g][m] = Math
//								.min(utm.preGMRating[g][m], utm.preUMRating[utm.userListTrain
//										.indexOf(user.getKey())][m]);
//					}
//				}
//			}
//			break;
//		case avg:
//			for (int g = 0; g < utm.G; g++) {
//				for (int m = 0; m < utm.M; m++) {
//					utm.preGMRating[g][m] = 0;
//					for (Entry<Integer, Integer> user : utm.allGroups[g].users
//							.entrySet()) {
//						utm.preGMRating[g][m] += utm.preUMRating[utm.userListTrain
//								.indexOf(user.getKey())][m];
//					}
//					utm.preGMRating[g][m] /= utm.allGroups[g].users.size();
//				}
//			}
//			break;
//		}
		utm.maeAucPcsMapRecallUser(UtmRwr_Model.Model.pmf,policy);
	}
	
	static void mfrwr(UtmRwr_Model.Policy policy){
		switch(policy){
		case wtd:
			for (int g = 0; g < utm.G; g++) {
				float sumOfNum = 0;
				for (int n : utm.allGroups[g].users.values()) 
					sumOfNum += n;
				for (int m = 0; m < utm.M; m++) {
					for (Entry<Integer, Integer> user : utm.allGroups[g].users.entrySet()) {
						utm.preGMRating[g][m] += user.getValue() / sumOfNum * utm.preUMRating[utm.userListTrain.indexOf(user.getKey())][m];
					}
				}
			}
			break;
		case lm:
			for (int g = 0; g < utm.G; g++) {
				for (int m = 0; m < utm.M; m++) {
					utm.preGMRating[g][m]=Integer.MAX_VALUE;
					for (Entry<Integer, Integer> user : utm.allGroups[g].users.entrySet()) {
						utm.preGMRating[g][m] = Math.min(utm.preGMRating[g][m], utm.preUMRating[utm.userListTrain.indexOf(user.getKey())][m]);
					}
				}
			}
			break;
		case avg:
			for (int g = 0; g < utm.G; g++) {
				for (int m = 0; m < utm.M; m++) {
					utm.preGMRating[g][m]=0;
					for (Entry<Integer, Integer> user : utm.allGroups[g].users.entrySet()) {
						utm.preGMRating[g][m] += utm.preUMRating[utm.userListTrain.indexOf(user.getKey())][m];
					}
					utm.preGMRating[g][m] /= utm.allGroups[g].users.size();
				}
			}
			break;
		}		

		try {
			utm.maeAucPcsMapRecall(UtmRwr_Model.Model.pmf,policy);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	static void arrayListToFile(ArrayList<Integer> list,String fileName){
		try{
			ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(fileName));
			os.writeObject(list);
			os.close();
		} catch(Exception e){
			e.printStackTrace();
		}
	}
	
	static void arrayListToFile(UtmRwr_Model.Model model, UtmRwr_Model.Policy policy, ArrayList<Integer> list,String fileName){
		String basePath = "./"+model+"/"+policy +"/";
		try{
			ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(basePath+fileName));
			os.writeObject(list);
			os.close();
		} catch(Exception e){
			e.printStackTrace();
		}
	}
	
	static ArrayList<Integer> fileToArrayList(String fileName){
		ArrayList<Integer> list = null;
		try{
			ObjectInputStream is = new ObjectInputStream(new FileInputStream(fileName));
			list = (ArrayList<Integer>)is.readObject();
			is.close();
		} catch(Exception e){
			e.printStackTrace();
		}
		return list;
	}
	
}
